
#include "RtBase.h"
#include "RtMessageBlock.h"
#include "RtDataBlock.h"

#ifdef RT_DEBUG
	#define SELFCHECK_MessageBlock(pmb) \
	do { \
		RT_ASSERTE(pmb->m_pBeginPtr <= pmb->m_pReadPtr); \
		RT_ASSERTE(pmb->m_pReadPtr <= pmb->m_pWritePtr); \
		RT_ASSERTE(pmb->m_pWritePtr <= pmb->m_pEndPtr); \
	} while (0)
#else
	#define SELFCHECK_MessageBlock(pmb)
#endif // RT_DEBUG

INT CRtMessageBlock::s_block_createcount = 0;
INT CRtMessageBlock::s_block_destoycount = 0;

CRtString CRtMessageBlock::GetBlockStatics()
{
	char szBuffer[128] = {0};
	snprintf(szBuffer, sizeof(szBuffer), 
		" [msgblock c-%d d-%d]",
		s_block_createcount, s_block_destoycount);
	return CRtString(szBuffer);
}

CRtMessageBlock::CRtMessageBlock(DWORD aSize, LPCSTR aData, MFlag aFlag, DWORD aAdvanceWritePtrSize)
	: m_pNext(NULL)
	, m_pSaveReadPtr(NULL)
	, m_Flag(0)
	
{
	++ s_block_createcount;
	if (aData && RT_BIT_DISABLED(aFlag, CRtMessageBlock::MALLOC_AND_COPY)) {
		RT_SET_BITS(aFlag, CRtMessageBlock::DONT_DELETE);
		m_pBeginPtr = aData;
		m_pReadPtr = m_pBeginPtr;
		m_pWritePtr = const_cast<LPSTR>(m_pBeginPtr);
		m_pEndPtr = aData + aSize;
	}
	else {
#ifdef RT_DEBUG
		if (aData)
			RT_ASSERTE(RT_BIT_DISABLED(aFlag, CRtMessageBlock::DONT_DELETE));
#endif // RT_DEBUG
		RT_CLR_BITS(aFlag, CRtMessageBlock::DONT_DELETE);
		if (aSize > 0)
			CRtDataBlock::CreateInstance(m_pDataBlock.ParaOut(), aSize);
		Reset(m_pDataBlock.ParaIn());
	}
	
	if (aAdvanceWritePtrSize > 0)
		AdvanceTopLevelWritePtr(aAdvanceWritePtrSize);
	
	m_Flag = aFlag;
	RT_CLR_BITS(m_Flag, CRtMessageBlock::MALLOC_AND_COPY);
	RT_CLR_BITS(m_Flag, CRtMessageBlock::INTERNAL_MASK);
}

CRtMessageBlock::CRtMessageBlock(CRtDataBlock *aDb, MFlag aFlag)
	: m_pNext(NULL)
	, m_pSaveReadPtr(NULL)
{
	++ s_block_createcount;
	RT_ASSERTE(RT_BIT_DISABLED(aFlag, CRtMessageBlock::DONT_DELETE));
	RT_CLR_BITS(aFlag, CRtMessageBlock::DONT_DELETE);
	
	Reset(aDb);

	m_Flag = aFlag;
	RT_CLR_BITS(m_Flag, CRtMessageBlock::MALLOC_AND_COPY);
	RT_CLR_BITS(m_Flag, CRtMessageBlock::INTERNAL_MASK);
}

/*
#if 0
CRtMessageBlock::CRtMessageBlock(const CRtMessageBlock &aCopy)
	: m_pNext(NULL)
	, m_pReadPtr(NULL)
	, m_pWritePtr(NULL)
	, m_pBeginPtr(NULL)
	, m_pEndPtr(NULL)
	, m_Flag(0)
{
	(*this) = aCopy;
}

void CRtMessageBlock::operator = (const CRtMessageBlock &aCopy)
{
	// We can't malloc m_pNext in this assign operator.
	RT_ASSERTE(!aCopy.m_pNext);
	m_pNext = NULL;

	Reset(aCopy.m_pDataBlock.ParaIn());
	m_pReadPtr += aCopy.m_pReadPtr - aCopy.m_pBeginPtr;
	m_pWritePtr += aCopy.m_pWritePtr - aCopy.m_pBeginPtr;
	m_Flag = aCopy.m_Flag;
	SELFCHECK_MessageBlock(this);
}
#endif
*/

CRtMessageBlock::~CRtMessageBlock()
{
	++ s_block_destoycount;
}

RtResult CRtMessageBlock::Peek(LPVOID aDst, DWORD aCount, DWORD aPos, DWORD* aBytesRead)
{
	RT_ASSERTE(RT_BIT_DISABLED(m_Flag, READ_LOCKED));
	DWORD dwLen = GetTopLevelLength();
	DWORD dwHaveRead = 0;
	
	RT_ASSERTE(m_pWritePtr >= m_pReadPtr);
	if(aPos >= dwLen)
	{
		aPos -= dwLen;
		if(m_pNext)
			return m_pNext->Peek(aDst, aCount, aPos, aBytesRead);
		return RT_ERROR_PARTIAL_DATA;
	}

	if(dwLen >= aCount + aPos)
	{
		if (aDst)
			::memcpy((LPSTR)aDst+dwHaveRead, m_pReadPtr + aPos, aCount);
		dwHaveRead += aCount;
		if (aBytesRead)
			*aBytesRead = dwHaveRead;
		return RT_OK;
	}
	else {
		if (aDst)
			::memcpy((LPSTR)aDst+dwHaveRead, m_pReadPtr + aPos, dwLen - aPos);
		dwHaveRead += (dwLen - aPos);
		if (m_pNext) {
			DWORD dwNextRead;
			RtResult rv = m_pNext->Read(
				aDst ? (LPSTR)aDst+dwHaveRead : aDst, 
				aCount- dwHaveRead, 
				&dwNextRead, 
				FALSE);
			dwHaveRead += dwNextRead;
			if (aBytesRead)
				*aBytesRead = dwHaveRead;
			return rv;
		}
		else {
			if (aBytesRead)
				*aBytesRead = dwHaveRead;
			return RT_ERROR_PARTIAL_DATA;
		}
	}
}

RtResult CRtMessageBlock::Read(LPVOID aDst, DWORD aCount, DWORD *aBytesRead, BOOL aAdvance) 
{
#if 0
	RT_ASSERTE(RT_BIT_DISABLED(m_Flag, READ_LOCKED));
	DWORD dwLen = GetTopLevelLength();
	DWORD dwHaveRead = 0;
	
	RT_ASSERTE(m_pWritePtr >= m_pReadPtr);
	if (dwLen >= aCount) {
		if (aDst)
			::memcpy((LPSTR)aDst+dwHaveRead, m_pReadPtr, aCount);
		dwHaveRead += aCount;
		if (aAdvance) {
			m_pReadPtr += aCount;
			RT_ASSERTE(m_pReadPtr <= m_pWritePtr);
		}
		if (aBytesRead)
			*aBytesRead = dwHaveRead;
		return RT_OK;
	}
	else {
		if (aDst)
			::memcpy((LPSTR)aDst+dwHaveRead, m_pReadPtr, dwLen);
		dwHaveRead += dwLen;
		if (aAdvance) {
			m_pReadPtr += dwLen;
			RT_ASSERTE(m_pReadPtr == m_pWritePtr);
		}
		if (m_pNext) {
			DWORD dwNextRead;
			RtResult rv = m_pNext->Read(
				aDst ? (LPSTR)aDst+dwHaveRead : aDst, 
				aCount-dwLen, 
				&dwNextRead, 
				aAdvance);
			dwHaveRead += dwNextRead;
			if (aBytesRead)
				*aBytesRead = dwHaveRead;
			return rv;
		}
		else {
			if (aBytesRead)
				*aBytesRead = dwHaveRead;
			return RT_ERROR_PARTIAL_DATA;
		}
	}
#else
	CRtMessageBlock *pMbMove = this;
	DWORD dwHaveRead = 0;
	BOOL bPartial = TRUE;

	while(pMbMove)
	{
		RT_ASSERTE(RT_BIT_DISABLED(pMbMove->m_Flag, READ_LOCKED));
		RT_ASSERTE(pMbMove->m_pWritePtr >= pMbMove->m_pReadPtr);
		DWORD dwLen = pMbMove->GetTopLevelLength();
		DWORD dwNeedRead = aCount - dwHaveRead;
		dwNeedRead = (dwLen >= dwNeedRead) ? dwNeedRead : dwLen;
		if (aDst)
			::memcpy((LPSTR)aDst+dwHaveRead, pMbMove->m_pReadPtr, dwNeedRead);
		dwHaveRead += dwNeedRead;
		if (aAdvance) {
			pMbMove->m_pReadPtr += dwNeedRead;
			RT_ASSERTE(pMbMove->m_pReadPtr <= pMbMove->m_pWritePtr);
		}
		if(dwHaveRead >= aCount)
		{
			bPartial = FALSE;
			break;
		}
		pMbMove = pMbMove->m_pNext;
	}

	if (aBytesRead)
		*aBytesRead = dwHaveRead;

	return bPartial ? RT_ERROR_PARTIAL_DATA : RT_OK;
#endif
}

RtResult CRtMessageBlock::Write(LPCVOID aSrc, DWORD aCount, DWORD *aBytesWritten)
{
	RT_ASSERTE(RT_BIT_DISABLED(m_Flag, WRITE_LOCKED));
	DWORD dwSpace = GetTopLevelSpace();
	DWORD dwHaveWritten = 0;

	if (dwSpace >= aCount) {
		dwHaveWritten = aCount;
		if (aSrc)
			::memcpy(m_pWritePtr, aSrc, aCount);
		m_pWritePtr += aCount;
		if (aBytesWritten)
			*aBytesWritten = dwHaveWritten;
		return RT_OK;
	}
	else {
		dwHaveWritten = dwSpace;
		if (aSrc)
			::memcpy(m_pWritePtr, aSrc, dwSpace);
		m_pWritePtr += dwSpace;
		RT_ASSERTE(m_pWritePtr == m_pEndPtr);
		if (aBytesWritten)
			*aBytesWritten = dwHaveWritten;
		return RT_ERROR_PARTIAL_DATA;
	}
}

DWORD CRtMessageBlock::GetChainedLength() const
{
	DWORD dwRet = 0;
	const CRtMessageBlock *i = this;
	try
	{
		for (; NULL != i; i = i->m_pNext)
			dwRet += i->GetTopLevelLength();
	}
	catch (...)
	{
		RT_ERROR_TRACE_THIS("CRtMessageBlock::GetChainedLength, catch exception! i="<<i<<" len="<<dwRet
			<<" i->m_pWritePtr="<<(void*)i->m_pWritePtr<<" i->m_pReadPtr="<<(void*)i->m_pReadPtr);
		return 0;
	}
	return dwRet;
}

DWORD CRtMessageBlock::GetChainedSpace() const
{
	DWORD dwRet = 0;
	for (const CRtMessageBlock *i = this; NULL != i; i = i->m_pNext)
		dwRet += i->GetTopLevelSpace();
	return dwRet;
}

void CRtMessageBlock::Append(CRtMessageBlock *aMb)
{
	SELFCHECK_MessageBlock(aMb);
#if 1
	CRtMessageBlock *pMbMove = this;
	while (pMbMove) {
		RT_ASSERTE(aMb != pMbMove);
		if (pMbMove->m_pNext)
			pMbMove = pMbMove->m_pNext;
		else {
			pMbMove->m_pNext = aMb;
			return;
		}
	}

#else // Don't use recursion to avoid stack overflow
	RT_ASSERTE(aMb != this);
	if (m_pNext) {
		m_pNext->Append(aMb);
		return;
	}
	else {
		m_pNext = aMb;
	}
#endif // 1
}

RtResult CRtMessageBlock::AdvanceChainedReadPtr(DWORD aCount, DWORD *aBytesRead)
{
//	RT_ASSERTE(RT_BIT_DISABLED(m_Flag, READ_LOCKED));
	RtResult rv = Read(NULL, aCount, aBytesRead);
	return rv;
}

RtResult CRtMessageBlock::AdvanceChainedWritePtr(DWORD aCount, DWORD *aBytesWritten)
{
	RT_ASSERTE(RT_BIT_DISABLED(m_Flag, WRITE_LOCKED));
	DWORD dwNeedWrite = aCount;
	for (CRtMessageBlock *pCurrent = this; 
		 NULL != pCurrent && dwNeedWrite > 0; 
		 pCurrent = pCurrent->m_pNext) 
	{
		RT_ASSERTE(pCurrent->m_pBeginPtr == pCurrent->m_pReadPtr);
		if (pCurrent->m_pBeginPtr != pCurrent->m_pReadPtr) {
			RT_ERROR_TRACE("CRtMessageBlock::AdvanceChainedWritePtr, can't advance."
				" m_pBeginPtr=" << (LPVOID)pCurrent->m_pBeginPtr <<
				" m_pReadPtr=" << (LPVOID)pCurrent->m_pReadPtr);
			if (aBytesWritten)
				*aBytesWritten = aCount - dwNeedWrite;
			return RT_ERROR_PARTIAL_DATA;
		}

		DWORD dwLen = pCurrent->GetTopLevelSpace();
		if (dwNeedWrite <= dwLen) {
			pCurrent->AdvanceTopLevelWritePtr(dwNeedWrite);
			if (aBytesWritten)
				*aBytesWritten = aCount;
			return RT_OK;
		}
		else {
			dwNeedWrite -= dwLen;
			pCurrent->AdvanceTopLevelWritePtr(dwLen);
		}
	}

	RT_ASSERTE(aCount > dwNeedWrite);
	if (aBytesWritten)
		*aBytesWritten = aCount - dwNeedWrite;
	return RT_ERROR_PARTIAL_DATA;
}

CRtMessageBlock* CRtMessageBlock::DuplicateChained()
{
#if 1
	CRtMessageBlock *pRet = NULL;
	CRtMessageBlock *pNewMove = NULL;
	CRtMessageBlock *pOldMove = this;

	while (pOldMove) {
		CRtMessageBlock *pDuplicate = pOldMove->DuplicateTopLevel();
		if (!pDuplicate) {
			RT_WARNING_TRACE_THIS("CRtMessageBlock::DuplicateChained, return NULL from DuplicateTopLevel!");
			if (pRet)
				pRet->DestroyChained();
			return NULL;
		}

		if (!pRet) {
			pRet = pDuplicate;
			RT_ASSERTE(!pNewMove);
			pNewMove = pDuplicate;
		}
		else {
			RT_ASSERTE(pNewMove);
			pNewMove->m_pNext = pDuplicate;
			pNewMove = pDuplicate;
		}

		pOldMove = pOldMove->m_pNext;
	}
	return pRet;
#else // Don't use recursion to avoid stack overflow
	CRtMessageBlock *pRet = DuplicateTopLevel();
	if (pRet) {
		if (m_pNext) {
			pRet->m_pNext = m_pNext->DuplicateChained();
			if (!pRet->m_pNext) {
				pRet->DestroyChained();
				return NULL;
			}
		}
	}
	return pRet;
#endif // 1
}

CRtMessageBlock* CRtMessageBlock::DuplicateTopLevel() const 
{
	CRtMessageBlock *pRet = NULL;
	if (RT_BIT_ENABLED(m_Flag, CRtMessageBlock::DONT_DELETE)) {
		// <m_pBeginPtr> and <m_pEndPtr> are pointing to the actual data,  
		// and m_pDataBlock is NULL.
		RT_ASSERTE(!m_pDataBlock);
		
		DWORD dwLen = m_pEndPtr - m_pBeginPtr;
		MFlag flagNew = m_Flag;
		RT_CLR_BITS(flagNew, CRtMessageBlock::DONT_DELETE);
		RT_SET_BITS(flagNew, CRtMessageBlock::MALLOC_AND_COPY);
		pRet = new CRtMessageBlock(
			dwLen, 
			m_pBeginPtr, 
			flagNew);

		if (pRet && dwLen)
		{
			try
			{
				::memcpy(pRet->GetTopLevelWritePtr(), m_pBeginPtr, dwLen);
			}
			catch (...)
			{
				RT_ERROR_TRACE_THIS("CRtMessageBlock::DuplicateTopLevel, catch exception! len="<<dwLen<<" m_pBeginPtr="<<(void*)m_pBeginPtr);
				delete pRet;
				return NULL;
			}
		}
	}
	else {
		pRet = new CRtMessageBlock(m_pDataBlock.ParaIn(), m_Flag);
	}

	if (pRet) {
		/// <CRtDataBlock> maybe realloc if DONT_DELETE,
		/// so can't do "pRet->m_pReadPtr = m_pReadPtr;"
		pRet->m_pReadPtr += m_pReadPtr - m_pBeginPtr;
		pRet->m_pWritePtr += m_pWritePtr - m_pBeginPtr;
		RT_SET_BITS(pRet->m_Flag, DUPLICATED);
		SELFCHECK_MessageBlock(pRet);
	}
	return pRet;
}

CRtMessageBlock* CRtMessageBlock::Disjoint(DWORD aStart)
{
	if (aStart > GetChainedLength())
	{
		RT_WARNING_TRACE_THIS("CRtMessageBlock::Disjoint, start="<<aStart<<" len="<<GetChainedLength());
		return NULL;
	}

	// find the start point of disjointing.
	CRtMessageBlock *pFind = NULL;
	for (CRtMessageBlock *pCurrent = this; pCurrent; pCurrent = pCurrent->m_pNext) 
	{
		DWORD dwLen = pCurrent->GetTopLevelLength();
		if (aStart == 0 && dwLen == 0) {
		}
		else if (aStart == dwLen) {
			pFind = pCurrent->m_pNext;
			pCurrent->m_pNext = NULL;
			break;
		}
		else if (aStart < dwLen) {
			pFind = pCurrent->DuplicateTopLevel();
			if (pFind) {
				pFind->m_pNext = pCurrent->m_pNext;
				pFind->m_pReadPtr += aStart;
				SELFCHECK_MessageBlock(pFind);

				pCurrent->m_pWritePtr -= dwLen - aStart;
				pCurrent->m_pNext = NULL;
				SELFCHECK_MessageBlock(pCurrent);
			}
			else
				RT_WARNING_TRACE_THIS("CRtMessageBlock::Disjoint, return NULL from DuplicateTopLevel!");

			break;
		}
		else {
			aStart -= dwLen;
		}
	}
	
	// duplicate from <pFind>, if is DUPLICATED, need not duplicate again.
	CRtMessageBlock *pPrevious = NULL;
	CRtMessageBlock *pMove = pFind;
	while (pMove) {
		if (RT_BIT_DISABLED(pMove->m_Flag, DUPLICATED)) {
			RT_WARNING_TRACE("CRtMessageBlock::Disjoint, there are not DUPLICATED "
				"blocks behind the disjointed block.");
			CRtMessageBlock *pNew = pMove->DuplicateTopLevel();
			if (!pNew) {
				// the best way is rollback to destroy what duplicated in this function.
				// but duplicate failed will rare happen.
				return NULL;
			}
			if (pFind == pMove) {
				// the <pFind> is not DUPLICATED, replace it
				pFind = pNew;
			}
			else if (pPrevious) {
				RT_ASSERTE(pPrevious->m_pNext == pMove);
				pPrevious->m_pNext = pNew;
			}
			pNew->m_pNext = pMove->m_pNext;
			pMove->m_pNext = NULL;
			pMove = pNew->m_pNext;
			pPrevious = pNew;
		}
		else {
			pPrevious = pMove;
			pMove = pMove->m_pNext;
		}
	}
	return pFind;
}

void CRtMessageBlock::DestroyChained()
{
#if 1
	CRtMessageBlock *pMbMove = this;
	while (pMbMove) {
		RT_ASSERTE(RT_BIT_ENABLED(pMbMove->m_Flag, DUPLICATED));
		if (RT_BIT_DISABLED(pMbMove->m_Flag, DUPLICATED))
		{
			pMbMove = pMbMove->m_pNext;
			continue;
		}

		CRtMessageBlock *pTmp = pMbMove->m_pNext;
		delete pMbMove;
		pMbMove = pTmp;
	}
#else // Don't use recursion to avoid stack overflow
	if (m_pNext)
		m_pNext->DestroyChained();
	m_pNext = NULL;

	RT_ASSERTE_RETURN_VOID(RT_BIT_ENABLED(m_Flag, DUPLICATED));
	delete this;
#endif // 1
}

DWORD CRtMessageBlock::FillIov(
		iovec* inIov, 
		DWORD inMax, 
		DWORD& outFillLength, 
		const CRtMessageBlock*& outRemainder) const
{
	outFillLength = 0;
	DWORD fillNum =0;
	const CRtMessageBlock* i = this;
	for (; NULL != i && fillNum < inMax; i = i->m_pNext) 
	{
		DWORD dwLen = i->GetTopLevelLength();
		if (dwLen > 0) {
			inIov[fillNum].iov_base = const_cast<char*>(i->GetTopLevelReadPtr());
			inIov[fillNum].iov_len = dwLen;
			++fillNum;
			outFillLength += dwLen;
		}
	}
	outRemainder = i;
	return fillNum;
}

void CRtMessageBlock::RewindChained(BOOL bRead)
{
	// TODO: need record first read ptr
	for (CRtMessageBlock *i = this; NULL != i; i = i->m_pNext) {
		SELFCHECK_MessageBlock(i);
		if(bRead)
		{
			RT_ASSERTE(i->m_pSaveReadPtr);
			i->m_pReadPtr = i->m_pSaveReadPtr;
		}
		else
		{
			i->m_pWritePtr = const_cast<LPSTR>(m_pBeginPtr);
		}
	}
}

void CRtMessageBlock::SaveChainedReadPtr()
{
	for (CRtMessageBlock *i = this; NULL != i; i = i->m_pNext) {
		SELFCHECK_MessageBlock(i);
		i->m_pSaveReadPtr = i->m_pReadPtr;
	}
}

CRtMessageBlock* CRtMessageBlock::ReclaimGarbage()
{
	// find the start point of disjointing.
	CRtMessageBlock *pCurrent = this;
	while (pCurrent) 
	{
		DWORD dwLen = pCurrent->GetTopLevelLength();
		if (dwLen == 0) {
			CRtMessageBlock *pTmp = pCurrent->m_pNext;
			if (RT_BIT_ENABLED(pCurrent->m_Flag, DUPLICATED))
				delete pCurrent;
			pCurrent = pTmp;
		}
		else {
			return pCurrent;
		}
	}
	return NULL;
}

CRtString CRtMessageBlock::FlattenChained()
{
	CRtString strRet;
	strRet.reserve(GetChainedLength() + 1);

	for (CRtMessageBlock *i = this; NULL != i; i = i->m_pNext)
		strRet.append(
			i->GetTopLevelReadPtr(),
			i->GetTopLevelLength());

	return strRet;
}

